# Created by Gao Song on 2019-04-09

from .base_fucker import BaseFucker
from gateway.base_gateway import BaseGateway
from event import Event

from .base_fucker import FuckerStatus
from core.constant import Status as OrderStatus, Direction, Exchange, Offset, OrderType
import pandas as pd

import logging
logger = logging.getLogger('fucker')


class CloseLongShortFucker(BaseFucker):
    def __init__(self, gateway: BaseGateway):
        super().__init__(gateway)
        self.long_to_close = pd.Series()
        self.short_to_close = pd.Series()

    def set_task(self, target_pos):
        for vt_symbol, holding in self.position_management.holdings.items():
            if holding.long_pos > 0 and holding.short_pos > 0:
                pos = min(holding.long_pos, holding.short_pos)
                self.long_to_close[vt_symbol] = pos
                self.short_to_close[vt_symbol] = pos

        self.subscribe_symbols(list(self.long_to_close.keys()))
        self.finished = pd.Series(False, index=list(self.long_to_close.keys()))
        self.status = FuckerStatus.SET_TASK

    def start(self, at=None):
        if self.long_to_close is None or len(self.long_to_close) == 0:
            self.logger.info('nothing changed. exit.')
            self._stop()

        self.status = FuckerStatus.RUNNING

    def on_tick(self, e: Event):
        tick = e.data

        if self.status != FuckerStatus.RUNNING:
            return

        vt_symbol = tick.vt_symbol

        if self.finished[vt_symbol]:
            return

        self.check_cancel_orders(vt_symbol, tick.bid_price_1, tick.ask_price_1)

        trading_long, trading_short = self.check_trading(vt_symbol)

        symbol, exchange = vt_symbol.split('.')
        exchange = Exchange(exchange)
        lock = False

        if self.long_to_close[vt_symbol] > trading_long:
            pos = self.long_to_close[vt_symbol] - trading_long
            self.send_order(symbol, exchange, Direction.LONG, Offset.CLOSEYESTERDAY, tick.ask_price_1, pos, OrderType.LIMIT, lock)

        if self.short_to_close[vt_symbol] > trading_short:
            pos = self.short_to_close[vt_symbol] - trading_short
            self.send_order(symbol, exchange, Direction.SHORT, Offset.CLOSEYESTERDAY, tick.bid_price_1, pos, OrderType.LIMIT, lock)

    def on_trade(self, e: Event):
        if self.status == FuckerStatus.NOT_INITED:
            return

        trade = e.data

        self.position_management.update_trade(trade)
        self.logger.info(trade)

        if self.status != FuckerStatus.RUNNING:
            return

        if trade.direction == Direction.LONG:
            self.long_to_close[trade.vt_symbol] -= trade.volume
        elif trade.direction == Direction.SHORT:
            self.short_to_close[trade.vt_symbol] -= trade.volume

        if self.long_to_close[trade.vt_symbol] == 0 and self.short_to_close[trade.vt_symbol] == 0:
            self.end_symbol(trade.vt_symbol)

            if all(self.finished):
                self.logger.info('all finished.')
                self._stop()

    def check_cancel_orders(self, vt_symbol, bid_price, ask_price):
        for order in self.position_management.get_position_holding(vt_symbol).active_orders.values():
            if order.direction == Direction.LONG:
                price = ask_price
            else:
                price = bid_price

            if abs(order.price - price) >= 0.1:
                if order.status != OrderStatus.INIT:
                    logging.info(f'cancel: bid:{bid_price} ask:{ask_price} direct:{order.direction} pirce:{order.price}')
                    self.cancel_order(order)

    def check_trading(self, vt_symbol):
        trading_long = 0
        trading_short = 0
        for order in self.position_management.get_position_holding(vt_symbol).active_orders.values():

            trading = order.volume - order.traded
            if order.direction == Direction.LONG:
                trading_long += trading
            elif order.direction == Direction.SHORT:
                trading_short += trading

        return trading_long, trading_short
